package com.psy.counseling.utils;

import com.psy.counseling.properties.DataEncodeProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Base64Utils;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.KeyFactory;
import java.security.MessageDigest;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
 * @Author 梁学儒
 * @Date 2022/5/31 13:16
 * @Version 1.0
 */

@Component
public class DataEncode {

    @Autowired
    private DataEncodeProperties dataEncodeProperties;

    public DataEncode(DataEncodeProperties dataEncodeProperties) {
        this.dataEncodeProperties = dataEncodeProperties;
    }

    public DataEncode() {
    }

    //============================Base64 加密====================================

    /**
     * base64加密
     * @param str 需要加密的字符串
     * @return 加密后的字符串
     */
    public String encodeBae64(String str) {
        int size = dataEncodeProperties.getSize();
        String salt = dataEncodeProperties.getSalt();

        // 处理要加密的数据
        String encodeData = "{" + salt + "}" + str ;
        Base64.Encoder encoder = Base64.getEncoder();
        // 执行多次编码操作
        for (int x = 0 ; x < 1 ; x ++) {
            // 加密操作
            encodeData = encoder.encodeToString(encodeData.getBytes()) ;
        }
        return encodeData;
    }

    /**
     * Base64 解码
     * @param str 需要解密的字符串
     * @return 返回解密字符串
     */
    public String decodeBae64(String str) {

        // 获取加密次数
        int size = dataEncodeProperties.getSize();
        // 获取加密盐值
        String salt = dataEncodeProperties.getSalt();
        // 获得解密类
        Base64.Decoder decoder =  Base64.getDecoder();
        // 根据字节数组进行解密操作
        byte[] data = str.getBytes();
        for (int x = 0 ; x < 1; x ++) {
            //多次解密
            data = decoder.decode(data) ;
        }
        // 包含有盐值的数据
        String decodeData = new String(data) ;
        return decodeData.substring(("{" + salt + "}").length()) ;
    }


//=======================MD5 加密=======================================

    /**
     * MD5 加密
     * @param str  需要加密的字符串
     * @return 返回加密后的字符串
     */
    public String encodeMD5(String str) {
        try {
            // 生成一个MD5加密计算摘要
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] digest = md.digest((str + dataEncodeProperties.getSalt()).getBytes());
            return new String(Base64Utils.encode(digest));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

//========================公私秘钥加密=====================================


//    /**
//     * 公私秘钥加密
//     * @param str 需要加密的字符串
//     * @return 返回加密后的字符串
//     */
//    public String encodeRSA( String str) throws Exception {
//        if(str.length() > dataEncodeProperties.getMaxEncryptBlock()){
//            throw new Exception("加密的" + str + "长度过长，无法解密！");
//        }
//
//        // 获取公钥
//        String publicKey = dataEncodeProperties.getPublicKey();
//        String encode = null;
//        try{
//            //分段加密
//            byte[] decoded = org.apache.commons.codec.binary.Base64.decodeBase64(publicKey);
//            RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
//            Cipher cipher = Cipher.getInstance("RSA");
//            cipher.init(Cipher.ENCRYPT_MODE, pubKey);
//            byte[] bytes = str.getBytes();
//            int inputLen = bytes.length;
//            //偏移量
//            int offLen = 0;
//            int i = 0;
//            ByteArrayOutputStream bops = new ByteArrayOutputStream();
//            while(inputLen - offLen > 0){
//                byte [] cache;
//                if(inputLen - offLen > 117){
//                    cache = cipher.doFinal(bytes, offLen,117);
//                }else{
//                    cache = cipher.doFinal(bytes, offLen,inputLen - offLen);
//                }
//                bops.write(cache);
//                i++;
//                offLen = 117 * i;
//            }
//            bops.close();
//            byte[] encryptedData = bops.toByteArray();
//            encode = org.apache.commons.codec.binary.Base64.encodeBase64String(encryptedData);
//
//        }catch (Exception e){
//            System.out.println(e.getMessage());
//        }
//        return encode;
//
//    }
//
//    /**
//     * 公私秘钥解密
//     * @param str 需要解密的字符串
//     * @return 返回解密后的字符串
//     */
//    public String decodeRSA(String str) throws Exception {
//        if(str.length() > dataEncodeProperties.getKeySize()){
//            throw new Exception("加密的" + str + "长度过长，无法解密！");
//        }
//
//        // 获取私钥
//        String privateKey = dataEncodeProperties.getPrivateKey();
//        String decode = null;
//        try{
//            //分段解密
//            byte[] decoded = org.apache.commons.codec.binary.Base64.decodeBase64(privateKey);
//            RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
//            Cipher cipher = Cipher.getInstance("RSA");
//            cipher.init(Cipher.DECRYPT_MODE, priKey);
//            byte[] bytes = org.apache.commons.codec.binary.Base64.decodeBase64(str);
//            decode = getString(cipher, bytes);
//
//        }catch (Exception e){
//            System.out.println(e.getMessage());
//        }
//        return decode;
//    }

    private static String getString(Cipher cipher, byte[] bytes){
        int inputLen = bytes.length;
        int offLen = 0;
        int i = 0;
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        try{
            while(inputLen - offLen > 0){
                byte[] cache;
                if(inputLen - offLen > 128){
                    cache = cipher.doFinal(bytes,offLen,128);
                }else{
                    cache = cipher.doFinal(bytes,offLen,inputLen - offLen);
                }
                byteArrayOutputStream.write(cache);
                i++;
                offLen = 128 * i;
            }
            byteArrayOutputStream.close();
        }catch (Exception e){
            System.out.println(e.getMessage());
        }

        byte[] byteArray = byteArrayOutputStream.toByteArray();
        return new String(byteArray);
    }
}
